<template>
  <div>
    <a-modal
      v-model:open="open"
      title="图片编辑"
      :footer="false"
      @cancel="handleCancel"
      class="image-cropper"
    >
      <vue-cropper
        ref="cropperRef"
        :img="imageUrl"
        :autoCrop="true"
        :fixedBox="false"
        :centerBox="true"
        :canMoveBox="true"
        :info="true"
        outputType="png"
      />
      <div style="margin-bottom: 16px" />
      <!--      协同编辑,团队空间才展示-->
      <div class="image-cropper-collaboration-actions">
        <a-space v-if="props.spaceType === SPACE_TYPE_ENUM.TEAM">
          <a-button @click="doEnterEdit" v-if="canEnterEdit">进入编辑</a-button>
          <a-button @click="doExitEdit" v-if="canExitEdit">退出编辑</a-button>
          <label v-if="currenEditUser">{{ currenEditUser.userName }}正在编辑</label>
        </a-space>
      </div>
      <div style="margin-bottom: 16px" />
      <!-- 图片操作 -->
      <div class="image-cropper-actions">
        <a-space>
          <!--          canEnterEdit:{{ canEnterEdit }} currenEditUser:{{ currenEditUser }}-->
          <a-button
            @click="rotateLeft"
            :disabled="!canDoEdit && props.spaceType === SPACE_TYPE_ENUM.TEAM"
            >向左旋转</a-button
          >
          <a-button
            @click="rotateRight"
            :disabled="!canDoEdit && props.spaceType === SPACE_TYPE_ENUM.TEAM"
            >向右旋转</a-button
          >
          <a-button
            @click="changeScale(1)"
            :disabled="!canDoEdit && props.spaceType === SPACE_TYPE_ENUM.TEAM"
            >放大</a-button
          >
          <a-button
            @click="changeScale(-1)"
            :disabled="!canDoEdit && props.spaceType === SPACE_TYPE_ENUM.TEAM"
            >缩小</a-button
          >
          <a-button
            @click="doCropper"
            :loading="loading"
            :disabled="!canDoEdit && props.spaceType === SPACE_TYPE_ENUM.TEAM"
            >确认</a-button
          >
        </a-space>
      </div>
    </a-modal>
  </div>
</template>

<script setup lang="ts">
import { computed, onUnmounted, ref, watchEffect } from 'vue'
import { uploadPictureUsingPost } from '@/api/fileController.ts'
import { message } from 'ant-design-vue'
import { useLoginUserStore } from '@/stores/userLoginUserStore.ts'
import PictureEditWebSocket from '@/utils/websocket.ts'
import { PICTURE_EDIT_ACTION_ENUM, PICTURE_EDIT_MESSAGE_TYPE_ENUM } from '@/constants/picture.ts'
import { SPACE_TYPE_ENUM } from '@/constants/spaceUser.ts'

//控制是否打开
const open = ref<boolean>(false)

interface Props {
  //回显的图片url
  imageUrl?: string
  //空间id
  spaceId?: number
  //图片对象
  picture?: API.PictureVO
  //上传成功之后的回调
  onSuccess: (newPicture: API.PictureVO) => void
  //空间类型：0-私有 1-团队
  spaceType?: number
}

const props = defineProps<Props>()

// 编辑器组件的引用
const cropperRef = ref()

const loading = ref<boolean>(false)

// 向左旋转
const rotateLeft = () => {
  cropperRef.value.rotateLeft()
  doEditAction(PICTURE_EDIT_ACTION_ENUM.ROTATE_LEFT)
}

// 向右旋转
const rotateRight = () => {
  cropperRef.value.rotateRight()
  doEditAction(PICTURE_EDIT_ACTION_ENUM.ROTATE_RIGHT)
}

// 缩放
const changeScale = (num: number) => {
  cropperRef.value.changeScale(num)
  if (num === 1) {
    doEditAction(PICTURE_EDIT_ACTION_ENUM.ZOOM_IN)
  } else {
    doEditAction(PICTURE_EDIT_ACTION_ENUM.ZOOM_OUT)
  }
}

/**
 * 确认
 */
function doCropper() {
  loading.value = true
  //组装file对象
  cropperRef.value.getCropBlob((blob: Blob) => {
    const fileName = (props.picture?.name || 'image') + '.png'
    const file = new File([blob], fileName, { type: blob.type })
    uploadPicture({ file })
  })
}

/**
 * 上传图片的方法
 * @param file
 */
async function uploadPicture({ file }: any) {
  loading.value = true
  //这里的picture对象，是父组件传递过来的
  const params: API.PictureUploadRequest = props.picture ? { id: props.picture.id } : {}
  //如果是在私有空间上传，是具有spaceId的
  params.spaceId = props.spaceId

  const resp = await uploadPictureUsingPost(params, {}, file)
  if (resp.data.code === 0 && resp.data.data) {
    message.success('图片上传成功')
    //将上传成功的图片信息传递给父组件
    //子组件在图片上传成功后，通过 props.onSuccess?.(resp.data.data) 调用该回调，将新的图片信息传递回父组件
    handleCancel()
    props.onSuccess?.(resp.data.data)
  } else if (resp.data.code === 40100) {
    message.error('图片上传失败：' + resp.data.message)
  } else {
    message.error('图片上传错误：' + resp.data.message)
  }
  loading.value = false
}

/**
 * 关闭弹窗
 * @param e
 */
const handleCancel = () => {
  console.log('关闭')
  open.value = false
  if (webSocket) {
    webSocket.disconnect()
  }
  currenEditUser.value = undefined
}

/**
 * 打开
 */
const handleOpen = () => {
  open.value = true
}

/**
 * 暴露给父组件
 */
defineExpose({
  handleOpen,
})

const loginUser = useLoginUserStore().loginUser
//正在编辑的用户
const currenEditUser = ref<API.UserVO>()
//当前用户是否可以进入编辑
const canEnterEdit = computed(() => {
  return !currenEditUser.value
})
//当前用户是否可以编辑
const canDoEdit = computed(() => {
  return currenEditUser.value?.id === loginUser.id
})
//当前用户是否可以退出编辑
const canExitEdit = computed(() => {
  return currenEditUser.value?.id === loginUser.id
})

//定义ws
let webSocket: PictureEditWebSocket | null

const initWebSocket = () => {
  const pictureId = props.picture?.id
  if (!pictureId || !open.value) {
    return
  }
  if (webSocket) {
    webSocket.disconnect()
  }
  webSocket = new PictureEditWebSocket(pictureId)
  //建立连接
  webSocket.connect()

  //监听后端的消息 这里相当于连接建立
  webSocket.on(PICTURE_EDIT_MESSAGE_TYPE_ENUM.INFO, (msg) => {
    console.log('收到通知消息:', msg)
    message.info(msg.message)
    if (msg.currentEditUser) {
      currenEditUser.value = msg.currentEditUser
    }
    if ((msg.latestAction && msg.latestAction.length > 0)  && loginUser.userName !== currenEditUser.value?.userName) {
      //执行操作
      msg.latestAction.forEach(action => {
        switch (action) {
          case PICTURE_EDIT_ACTION_ENUM.ZOOM_IN:
            cropperRef.value.changeScale(1)
            break
          case PICTURE_EDIT_ACTION_ENUM.ZOOM_OUT:
            cropperRef.value.changeScale(-1)
            break
          case PICTURE_EDIT_ACTION_ENUM.ROTATE_LEFT:
            cropperRef.value.rotateLeft()
            break
          case PICTURE_EDIT_ACTION_ENUM.ROTATE_RIGHT:
            cropperRef.value.rotateRight()
            break
        }
      })
    }
  })

  webSocket.on(PICTURE_EDIT_MESSAGE_TYPE_ENUM.ERROR, (msg) => {
    console.log('收到错误消息:', msg)
    message.info(msg.message)
  })

  webSocket.on(PICTURE_EDIT_MESSAGE_TYPE_ENUM.ENTER_EDIT, (msg) => {
    console.log('收到进入编辑状态消息:', msg)
    message.info(msg.message)
    currenEditUser.value = msg.user
    console.log(currenEditUser.value)
  })

  webSocket.on(PICTURE_EDIT_MESSAGE_TYPE_ENUM.EDIT_ACTION, (msg) => {
    console.log('收到执行编辑消息:', msg)
    message.info(msg.message)
    switch (msg.editAction) {
      case PICTURE_EDIT_ACTION_ENUM.ZOOM_IN:
        cropperRef.value.changeScale(1)
        break
      case PICTURE_EDIT_ACTION_ENUM.ZOOM_OUT:
        cropperRef.value.changeScale(-1)
        break
      case PICTURE_EDIT_ACTION_ENUM.ROTATE_LEFT:
        cropperRef.value.rotateLeft()
        break
      case PICTURE_EDIT_ACTION_ENUM.ROTATE_RIGHT:
        cropperRef.value.rotateRight()
        break
    }
  })

  webSocket.on(PICTURE_EDIT_MESSAGE_TYPE_ENUM.EXIT_EDIT, (msg) => {
    console.log('收到退出编辑状态消息:', msg)
    message.info(msg.message)
    currenEditUser.value = undefined
  })
}

/**
 * 进入编辑
 * 向后端发送进入编辑操作事件
 */
function doEnterEdit() {
  //如果当前有websocket链接，则发送进入编辑操作事件
  if (webSocket) {
    webSocket.sendMessage({
      type: PICTURE_EDIT_MESSAGE_TYPE_ENUM.ENTER_EDIT,
    })
  }
}

/**
 * 退出编辑
 * 向后端发送退出编辑操作事件
 */
function doExitEdit() {
  if (webSocket) {
    webSocket.sendMessage({
      type: PICTURE_EDIT_MESSAGE_TYPE_ENUM.EXIT_EDIT,
    })
  }
}

/**
 * 执行具体编辑的操作
 * 向后端发送执行具体操作事件
 * @param action
 */
function doEditAction(action: any) {
  if (webSocket) {
    webSocket.sendMessage({
      type: PICTURE_EDIT_MESSAGE_TYPE_ENUM.EDIT_ACTION,
      editAction: action,
    })
  }
}

watchEffect(() => {
  if (props.spaceType === SPACE_TYPE_ENUM.TEAM) {
    initWebSocket()
  }
})

onUnmounted(() => {
  if (webSocket) {
    webSocket.disconnect()
  }
  currenEditUser.value = undefined
})
</script>

<style>
.image-cropper {
  text-align: center;
}

.image-cropper .vue-cropper {
  height: 400px !important;
}
</style>
